<template>
  <div id="map" ref="mapRef"></div>
  <button @click="onlyShow = !onlyShow">
    {{ !onlyShow ? '只显示0-60' : '显示全部' }}
  </button>
  <!-- <div
    ref="markerRef"
    class="marker"
    @click.stop="showDetail = false"
  >
  -->
  <!-- v-show="showDetail" -->
  <!-- <span>距离：80km</span>  -->
  <!-- </div> -->
</template>

<script lang="ts">
import { defineComponent, onMounted, ref, Ref, watch } from 'vue'
import mapboxgl from 'mapbox-gl'
import 'mapbox-gl/dist/mapbox-gl.css'
import * as turf from '@turf/turf'
const GZ_GEOJSON = require('./assets/GZ.json')

export default defineComponent({
  name: 'App',
  setup () {
    // const getRadiofunc = (): Array<string> => [
    //   '0-20',
    //   '21-40',
    //   '41-60',
    //   '61-100'
    // ]

    /**
     * ! State
     */
    const map: Ref = ref()
    // const filterRules: Ref = ref(['<=', 'loss', 100])
    const onlyShow: Ref<boolean> = ref(false)
    const showDetail: Ref<boolean> = ref(false)
    const markerRef = ref()
    const mapRef = ref()

    /**
     * ! watch
     */
    /* 切换 */
    watch(onlyShow, (val: boolean) => {
      val
        ? map.value.setFilter('gzPoint', ['<=', 'loss', 60])
        : map.value.setFilter('gzPoint', ['<=', 'loss', 100])
    })

    // watch(
    //   radioArr,
    //   (val: Array<string>) => {
    //     const arr: Array<string | Array<number | string>> = [
    //       'all',
    //       ['<=', 'loss', 100]
    //     ]

    //     // val.map((v: string) => {
    //     //   if (v === '0-20') arr.push(['>=', 'loss', 0])
    //     //   if (v === '21-40') arr.push(['>=', 'loss', 21])
    //     //   if (v === '41-60') arr.push(['>=', 'loss', 41])
    //     //   if (v === '61-100') arr.push(['>=', 'loss', 61])
    //     // })
    //     filterRules.value = arr
    //     console.log(filterRules)
    //   },
    //   { deep: true, immediate: true }
    // )
    /**
     * ! Function
     */
    /* 初始化地图 */
    const initMapFunc = (): void => {
      mapboxgl.accessToken =
        'pk.eyJ1Ijoic2FnaXQtemgiLCJhIjoiY2t0bnl5dDFnMDZ0aTJwcDNsa3N4emF1biJ9.jFO8rJJN-kvaz9vuQ0odKQ'
      map.value = new mapboxgl.Map({
        container: 'map',
        center: [113.3111, 23.0857],
        zoom: 7,
        style: 'mapbox://styles/mapbox/streets-v11',
        hash: true
      })
    }

    /* 圈出广州区域 */
    const drawGzAreaFunc = (): void => {
      map.value.on('load', () => {
        map.value.addSource('gz-geojson', { type: 'geojson', data: GZ_GEOJSON })
        map.value.addLayer({
          id: 'gzArea',
          type: 'line',
          source: 'gz-geojson',
          paint: { 'line-color': 'pink', 'line-width': 5 }
        })
      })
    }

    /* 随机选取 50 个坐标 */
    const draw50pointFunc = (): void => {
      /* 1. 生成坐标 */
      const gzPointGeojson: any = {
        type: 'FeatureCollection',
        features: []
      }
      // console.log(GZ_GEOJSON.features[0].geometry.coordinates)
      for (let i = 0; i < 50;) {
        const lng = Math.random() * 2 + 112.57 // 经度
        const lat = Math.random() * 2 + 22.26 // 纬度
        const range = GZ_GEOJSON.features[0].geometry.coordinates[0] // 范围区间

        const pt = turf.point([lng, lat]) // 取点
        const poly = turf.polygon(range) // 取范围
        const isIn = turf.booleanPointInPolygon(pt, poly) // 判断点是否在范围内

        if (isIn) {
          i++
          const point = {
            type: 'Feature',
            properties: { loss: Math.round(Math.random() * 100) },
            geometry: {
              type: 'Point',
              coordinates: [lng, lat]
            }
          }
          gzPointGeojson.features.push(point)
        }
      }

      /* 2. 添加画布 */
      map.value.on('load', () => {
        // const aaaa = turf.randomPoint(50, { bbox: [112.57, 22.26, 114.3, 23.56] })
        // const aaaa = turf.randomPoint(50, { bbox: GZ_GEOJSON })

        // console.log(aaaa)
        // console.log(gzPointGeojson)
        map.value.addSource('gzPoint', {
          type: 'geojson',
          data: gzPointGeojson
        })

        map.value.addLayer({
          id: 'gzPoint',
          type: 'circle',
          source: 'gzPoint',
          // paint: { 'circle-color': 'black' }
          paint: {
            'circle-color': {
              property: 'loss',
              stops: [
                [0, 'green'],
                [21, 'blue'],
                [41, 'orange'],
                [61, 'red']
              ]
            }
          }
        })

        // 鼠标指针
        map.value.on(
          'mouseenter',
          'gzPoint',
          () => (map.value.getCanvas().style.cursor = 'pointer')
        )

        map.value.on(
          'mouseleave',
          'gzPoint',
          () => (map.value.getCanvas().style.cursor = '')
        )
      })
    }

    // const handleCheckbox = (i: '0-20' | '21-40' | '41-60' | '61-100'): void => {
    //   console.log(i)
    //   const index: number = radioArr.value.findIndex((v: string) => v === i)
    //   console.log(index)
    //   if (index === -1) radioArr.value.push(i)
    //   else radioArr.value.splice(index, 1)
    // }

    /* 6 周边查询点 */
    const handleSearch = (): void => {
      const defaultData = {
        type: 'FeatureCollection',
        features: []
      }

      map.value.on('load', () => {
        map.value.addSource('searchArea', {
          type: 'geojson',
          data: defaultData
        })

        map.value.addLayer({
          id: 'searchArea',
          type: 'fill',
          source: 'searchArea',
          paint: { 'fill-color': 'black', 'fill-opacity': 0.3 }
        })
      })

      map.value.on('click', (e: any) => {
        // 查找点和范围
        const pointFeatures = map.value.queryRenderedFeatures(e.point, {
          // layers: ['gzPoint', 'searchArea']
          layers: ['gzPoint']
        })
        const areaFeatures = map.value.queryRenderedFeatures(e.point, {
          layers: ['searchArea']
        })
        // console.log(pointFeatures[0].geometry.coordinates)

        const closeArea = !pointFeatures.length && !areaFeatures.length
        if (closeArea) {
          map.value.getSource('searchArea').setData(defaultData)
          return false
        }
        if (areaFeatures.length) return false

        /**
         * 查询周边实现
         * 1. 点击点
         * 2. 生成范围
         * 3. 找出范围内的点
         * 4. 分别计算距离
         */

        // 2. 生成范围
        const center: [number, number] = pointFeatures[0].geometry.coordinates
        const area = turf.circle(center, 10, { steps: 24 })
        map.value.getSource('searchArea').setData(area)

        // 3. 范围内的点
        // console.log(map.value.getSource('gzPoint')._data)
        const gzPoint = map.value.getSource('gzPoint')._data // 所有的点
        // const allPoints = turf.coordAll(gzPoint) // 获取所有的点坐标
        // const allPointsGeojson = turf.points(allPoints) // 转成geojson
        const ptsWithin = turf.pointsWithinPolygon(gzPoint, area) // 在范围内的点
        // console.log(ptsWithin)
        const filterPts = ptsWithin.features.filter(
          (v: any) => Math.abs(center[0] - v.geometry.coordinates[0]) > 0.01
        ) // 排除自己
        console.log(filterPts)

        // 4. 计算距离数组并排序
        const distanceArr: number[] = filterPts
          .map((v: any) => turf.rhumbDistance(center, v.geometry.coordinates))
          .sort()

        const box: string[] = distanceArr.map(
          (v: number, index: number) => `<p>点${index + 1}距离：${v}km</p>`
        )

        // 5. 显示弹出层
        new mapboxgl.Popup()
          .setLngLat(center)
          .setHTML(`<p>附近有${filterPts.length}个点</p>${box}`)
          .addTo(map.value)
        // new mapboxgl.Marker(el).setLngLat(center).addTo(map.value)
      })
    }

    onMounted(() => {
      initMapFunc()
      drawGzAreaFunc()
      draw50pointFunc()
      handleSearch()
    })

    return { onlyShow, showDetail, markerRef, mapRef }
  }
})
</script>

<style lang="less">
body {
  display: flex;
  justify-content: center;
}

#map {
  width: 1000px;
  height: 500px;
}

.marker {
  /* background-image: url('https://docs.mapbox.com/mapbox-gl-js/assets/washington-monument.jpg'); */
  background-color: rgba(0, 0, 0, 0.5);
  /* background-size: cover; */
  /* width: 100px; */
  padding: 0 20px;
  height: 200px;
  border-radius: 5px;
  /* cursor: pointer; */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: space-evenly;
  color: #fff;
}
</style>
